package org.qiyu.live.bank.provider.service.impl;

import jakarta.annotation.Resource;
import org.idea.qiyu.live.framework.redis.starter.key.BankProviderCacheKeyBuilder;
import org.qiyu.live.bank.constants.TradeEnumType;
import org.qiyu.live.bank.dto.AccountTradeReqDTO;
import org.qiyu.live.bank.dto.AccountTradeRespDTO;
import org.qiyu.live.bank.provider.dao.mapper.IQiyuCurrencyAccountMapper;
import org.qiyu.live.bank.provider.dao.po.QiyuCurrencyAccountPO;
import org.qiyu.live.bank.provider.service.IQiyuCurrencyAccountService;
import org.qiyu.live.bank.provider.service.IQiyuCurrencyTradeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.*;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sfx
 * Date: 2023-11-03
 * Time: 19:06
 */
@Service
public class QiyuCurrencyAccountServiceImpl implements IQiyuCurrencyAccountService {

    private final Logger LOGGER = LoggerFactory.getLogger(QiyuCurrencyAccountServiceImpl.class);
    private static final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
            10,
            Runtime.getRuntime().availableProcessors() * 2,
            3000,
            TimeUnit.MINUTES,
            new ArrayBlockingQueue<>(1000),
            new ThreadFactory() {
                @Override
                public Thread newThread(Runnable runnable) {
                    Thread t = new Thread(runnable);
                    t.setName("sendGift - " + ThreadLocalRandom.current().nextInt(10000));
                    return t;
                }
            }
    );

    @Resource
    private IQiyuCurrencyAccountMapper accountMapper;

    @Resource
    private IQiyuCurrencyTradeService tradeService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private BankProviderCacheKeyBuilder cacheKeyBuilder;


    @Override
    public boolean insertOne(Long userId) {
        try {
            QiyuCurrencyAccountPO accountPO = new QiyuCurrencyAccountPO();
            accountPO.setUserId(userId);
            accountMapper.insert(accountPO);
            return true;
        } catch (Exception e) {
            LOGGER.error("[QiyuCurrencyAccountServiceImpl] 账户插入失败 可能是主键冲突", e);
        }
        return false;
    }


    @Override
    public void incr(Long userId, int num) {
        String key = cacheKeyBuilder.buildSendGiftCacheKey(userId);
        if(redisTemplate.hasKey(key)) {
            redisTemplate.opsForValue().decrement(key, num);
        }else {
            // 3. 异步的记录流水 + 扣减库存(落库)
            poolExecutor.execute(() -> {
                opDbIncrHandler(userId, num);
            });
        }
    }

    private void opDbIncrHandler(Long userId, int num) {
        // 插入流水记录
        tradeService.insertOne(userId, num, TradeEnumType.SEND_GIFT_TRADE.getCode());
        // 增加余额
        accountMapper.incr(userId, num);
    }


    @Override
    public void decr(Long userId, int num) {
        String key = cacheKeyBuilder.buildSendGiftCacheKey(userId);
        // 缓存存在,扣减缓存,不存在走db
        if(redisTemplate.hasKey(key)) {
            redisTemplate.opsForValue().decrement(key, num);
        }else {
            // 3. 异步的记录流水 + 扣减库存(落库)
            poolExecutor.execute(() -> {
                opDbDecrHandler(userId, num);
            });
        }
    }

    private void opDbDecrHandler(Long userId, int num) {
        // 插入流水记录
        tradeService.insertOne(userId, num, TradeEnumType.SEND_GIFT_TRADE.getCode());
        // 扣减余额
        accountMapper.decr(userId, num);
    }


    @Override
    public Integer getBalance(Long userId) {
        // 查询当前用户余额,我们使用redis进行优化
        if (userId == null || userId < 1L) {
            LOGGER.error("[QiyuCurrencyAccountServiceImpl] userId is error");
            return null;
        }
        // 1. 查询缓存
        String key = cacheKeyBuilder.buildBalanceCacheKey(userId);
        Integer balance = (Integer) redisTemplate.opsForValue().get(key);
        if (balance != null) {
            if (balance == -1) {
                // 空值缓存
                return null;
            }
            return balance;
        }
        // 2. 缓存不存在,查询数据库
        balance = accountMapper.getBalance(userId);
        if (balance == null) {
            // 设置空值缓存
            redisTemplate.opsForValue().set(key, -1L);
            return null;
        }
        redisTemplate.opsForValue().set(key, balance);
        return balance;
    }

    @Override
    public AccountTradeRespDTO consumeForGift(AccountTradeReqDTO accountTradeReqDTO) {
        // 1. 查询账户余额
        Long userId = accountTradeReqDTO.getUserId();
        Integer balance = this.getBalance(userId);
        if (balance == null || balance < 0) {
            return AccountTradeRespDTO.buildFail(userId, "余额不足", 1);
        }
        // 2. 账户余额充足,现在redis进行扣减
        this.decr(userId, accountTradeReqDTO.getNum());
        return AccountTradeRespDTO.buildSuccess(userId, "扣减成功");
    }
}